﻿using BZ.Core;
using NDK.Motion.Card;
using System;
using System.Diagnostics;
using System.Threading;

namespace NDK.Motion.MachineResources
{
    [Serializable]

    public class OutputSetting
    {
        #region Model
        private int _Id;
        private string _OutputName;
        private int _ModuleName;
        private int _Port;
        private ICard _card;
        private EFFECTIVE_LEVEL_ENUM _EffectiveLevel = EFFECTIVE_LEVEL_ENUM.High;//有效电平：true:高电平有效；false:低电平有效
        /// <summary>
        /// 
        /// </summary>
        public EFFECTIVE_LEVEL_ENUM EffectiveLevel
        {
            set { _EffectiveLevel = value; }
            get { return _EffectiveLevel; }
        }
        public OutputSetting()
        {
        }

        public OutputSetting(string name, ICard card, int port)
        {
            this._card = card;
            this._Port = port;
            this._OutputName = name;
        }
        /// <summary>
        /// 
        /// </summary>
        public int ID
        {
            set
            {
                _Id = value;
            }
            get
            {
                return _Id;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public string Name
        {
            set
            {
                _OutputName = value;
            }
            get
            {
                return _OutputName;
            }
        }
        /// <summary>
        /// 端口所在模块，凌华总线卡一般就是从站号，脉冲卡就是卡号
        /// </summary>
        public int ModuleName
        {
            set
            {
                _ModuleName = value;
            }
            get
            {
                return _ModuleName;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public int Port
        {
            set
            {
                _Port = value;
            }
            get
            {
                return _Port;
            }
        }
        public ICard Card
        {
            set
            {
                _card = value;
            }
            get
            {
                return _card;
            }
        }
        //用于界面绑定显示
        public string CardType
        { get { return Card.CardType; } }
        public int CardID
        { get { return Card.CardID; } }
        public int Group
        {
            get; set;
        } = 0;

        #endregion Model


        /// <summary>
        /// 设置Output为有效电平，并且等待设置成功，如果等待timeout毫秒还未成功，返回失败
        /// </summary>
        /// <returns>设置成功返回true，设置失败为false</returns>
        public bool ON(int timeout = 999999)
        {
            Stopwatch sw = new Stopwatch();
            sw.Restart();
            bool ret = false;

            try
            {
                //本来处于有效电平状态，无需再设置
                if (GetStatus() == true)
                    return true;

                if (_EffectiveLevel == EFFECTIVE_LEVEL_ENUM.High)
                {
                    ret = Card.SetDO(_ModuleName, _Port, 1);//高电平有效
                }
                else
                {
                    ret = Card.SetDO(_ModuleName, _Port, 0);//低电平有效
                }

                if (ret == true && GetStatus() == true)//如果设置成功，复检IO状态
                {
                    return true;
                }
                else//如果设置失败，尝试继续设置
                {
                    while (GetStatus() == false || ret == false)
                    {
                        if (sw.ElapsedMilliseconds > timeout)
                        {
                            return false;
                        }
                        if (_EffectiveLevel ==  EFFECTIVE_LEVEL_ENUM.High)
                        {
                            ret = Card.SetDO(_ModuleName, _Port, 1);//高电平有效
                        }
                        else
                        {
                            ret = Card.SetDO(_ModuleName, _Port, 0);//低电平有效
                        }
                        Thread.Sleep(1);
                    }
                }
                ret = true;
            }
            catch (Exception ex)
            {
                throw new IOException("设置Output[:" + Name + "]时发生异常！" + ex.Message);
            }
            return ret;
        }
        /// <summary>
        /// 设置Output为无效电平,，并且等待设置成功，如果等待timeout毫秒还未成功，返回false
        /// </summary>
        /// <returns>设置成功返回true，设置失败为false</returns>
        public bool OFF(int timeout = 999999)
        {
            Stopwatch sw = new Stopwatch();
            sw.Restart();
            bool ret = false;
            try
            {
                //本来处于低电平状态，无需再设置
                if (GetStatus() == false)
                    return true;

                if (_EffectiveLevel ==  EFFECTIVE_LEVEL_ENUM.High)
                {
                    ret = Card.SetDO(_ModuleName, _Port, 0);//高电平有效
                }
                else
                {
                    ret = Card.SetDO(_ModuleName, _Port, 1);//低电平有效
                }
                if (ret == true && GetStatus() == false)//如果设置成功，复检IO状态
                {
                    return ret;
                }
                else//如果设置失败，尝试继续设置
                {
                    while (GetStatus() == true || ret == false)
                    {
                        if (sw.ElapsedMilliseconds > timeout)
                        {
                            return false;
                        }
                        if (_EffectiveLevel ==  EFFECTIVE_LEVEL_ENUM.High)
                        {
                            ret = Card.SetDO(_ModuleName, _Port, 0);//高电平有效
                        }
                        else
                        {
                            ret = Card.SetDO(_ModuleName, _Port, 1);//低电平有效
                        }
                        Thread.Sleep(1);
                    }
                }
                ret = true;
            }
            catch (Exception ex)
            {
                throw new IOException("设置Output[:" + Name + "]时发生异常！" + ex.Message);
            }
            return ret;
        }

        /// <summary>
        /// 切换Output状态,，并且等待设置成功，如果等待timeout毫秒还未成功，返回false
        /// </summary>
        /// <param name="timeout">ms</param>
        /// <returns></returns>
        public bool Toggle(int timeout = 999999)
        {
            Stopwatch sw = new Stopwatch();
            sw.Restart();
            bool ret = false;
            try
            {
                //当前处于低电平状态，设置高电平
                if (GetStatus() == false)
                {
                    return ON(timeout);
                }
                else if (GetStatus() == true)
                {
                    return OFF(timeout);
                }
            }
            catch (Exception ex)
            {
                throw new IOException("设置Output[:" + Name + "]时发生异常！" + ex.Message);
            }
            return ret;
        }

        /// <summary>
        /// 获取Output状态
        /// </summary>
        /// <returns>有效电平返回true，无效电平返回false</returns>
        /// <Exception>异常抛出，读取失败抛出异常</Exception>
        public bool GetStatus()
        {
            bool ret = false;
            try
            {
                ret = Card.GetDO(_ModuleName, _Port);
            }
            catch (Exception ex)
            {
                throw new IOException("获取Output[:" + Name + "]状态时发生异常！" + ex.Message);
            }

            if (_EffectiveLevel ==  EFFECTIVE_LEVEL_ENUM.High)
            {
                return ret;
            }
            else
            {
                return !ret;
            }
        }
        /// <summary>
        /// 等待DO变成有效电平
        /// </summary>
        /// <param name="timeout"></param>
        /// <returns></returns>
        public bool WaitON(int timeout = int.MaxValue)
        {
            bool isTimeout = false;
            Stopwatch sw = new Stopwatch();
            sw.Restart();
            try
            {
                while (GetStatus() == false)
                {
                    if (sw.ElapsedMilliseconds >= timeout)
                    {
                        return true;
                    }
                    Thread.Sleep(1);
                }
            }
            catch (Exception ex)
            {
                throw new IOException("OutputModel WaitON Exception:" + ex.Message);
            }
            return isTimeout;
        }

        /// <summary>
        /// 等待DO变成无效电平
        /// </summary>
        /// <param name="timeout"></param>
        /// <returns></returns>
        public bool WaitOFF(int timeout = int.MaxValue)
        {
            bool isTimeout = false;
            Stopwatch sw = new Stopwatch();
            sw.Restart();
            try
            {
                while (GetStatus() == true)
                {
                    if (sw.ElapsedMilliseconds >= timeout)
                    {
                        return true;
                    }
                    Thread.Sleep(1);
                }
            }
            catch (Exception ex)
            {
                throw new IOException("OutputModel WaitOFF Exception:" + ex.Message);
            }
            return isTimeout;
        }

    }
}
